using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using FireStarter.Base;
using FireStarterModeller.BO;
using FireStarterModeller.Test.BO;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using Habanero.BO.Loaders;
using NUnit.Framework;
using FireStarter.CodeGeneration;
using FireStarterModeller.Test;

namespace FireStarter.Test.CodeGeneration
{
    [TestFixture]
    public class TestBoProjectGenerator : TestProjectGeneratorBase
    {
        private static BoProjectGenerator CreateBoProjectReadyToGenerate()
        {
            BoProjectGenerator projectGenerator = new BoProjectGenerator();
            CreateSolutionGenerator(projectGenerator);
            projectGenerator.ProjectPath = GetRootedPath(Path.Combine(TEST_PROJECTS_FOLDER, GetRandomString()));
            projectGenerator.ProjectName = "TestProject.Bo";
            projectGenerator.SolutionGenerator.ClassDefsString = "<classes>" + TestUtilsCodeGen.GetRandomString() + "</classes>";
            return projectGenerator;
        }

        protected override IProjectGenerator CreateProjectReadyToGenerate()
        {
            return CreateBoProjectReadyToGenerate();
        }

        protected override IProjectGenerator CreateProjectGenerator()
        {
            return new BoProjectGenerator();
        }

        private void AssertProjectGeneratedCorrectly(BoProjectGenerator boProjectGenerator)
        {
            string libFolderName = boProjectGenerator.SolutionGenerator.HabaneroReferencePath;
            libFolderName = Utilities.GetRelativePath(libFolderName, boProjectGenerator.ProjectPath);
            string projectFileName = boProjectGenerator.ProjectFileName;
            Assert.IsTrue(Directory.Exists(boProjectGenerator.ProjectPath));
            Assert.IsTrue(File.Exists(projectFileName));
            ProjectFileManager projectFileManager = new ProjectFileManager(projectFileName, CodeTemplateEnum.CSharpVisualStudio2005);
            Assert.AreEqual(OutputType.Library, projectFileManager.OutputType);
            string projectFileContents = File.ReadAllText(projectFileName);
            StringAssert.Contains(@"<Compile Include=""Properties\AssemblyInfo.cs"" />", projectFileContents);
            AssertHasReference(projectFileContents, string.Format(@"{0}\Habanero.Base.dll", libFolderName));
            AssertHasReference(projectFileContents, string.Format(@"{0}\Habanero.BO.dll", libFolderName));
            AssertHasReference(projectFileContents, string.Format(@"{0}\Habanero.DB.dll", libFolderName));
            AssertHasNotReference(projectFileContents, string.Format(@"{0}\Habanero.Util.dll", libFolderName));
        }

        [Test]
        public void TestCreateBoProjectGenerator()
        {
            //---------------Set up test pack-------------------

            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            IProjectGenerator BoProjectGenerator = CreateProjectGenerator();
            //---------------Test Result -----------------------
            Assert.IsNotNull(BoProjectGenerator);
            Assert.IsInstanceOf(typeof(BoProjectGenerator), BoProjectGenerator);
        }

        [Test]
        public void TestGenerate_Fails_ModelClassesNotSet()
        {
            //---------------Set up test pack-------------------
            BoProjectGenerator boProjectGenerator = CreateBoProjectReadyToGenerate();
            boProjectGenerator.SolutionGenerator.ModelClasses = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(boProjectGenerator.SolutionGenerator.ModelClasses);
            //---------------Execute Test ----------------------
            Exception exception = null;
            try
            {
                boProjectGenerator.Generate();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            //---------------Test Result -----------------------
            Assert.IsNotNull(exception, "Exception Expected");
            Assert.IsInstanceOf(typeof(PropertyMissingException), exception);
            PropertyMissingException propertyMissingException = (PropertyMissingException)exception;
            Assert.AreEqual("ModelClasses", propertyMissingException.PropertyName);
        }

        [Test]
        public void TestGenerate_Creates_ProjectFile_IfDoesNotExist()
        {
            //---------------Set up test pack-------------------
            BoProjectGenerator boProjectGenerator = CreateBoProjectReadyToGenerate();
            //---------------Assert Precondition----------------
            Assert.IsFalse(File.Exists(boProjectGenerator.ProjectFileName));
            //---------------Execute Test ----------------------
            boProjectGenerator.Generate();
            //---------------Test Result -----------------------
            AssertProjectGeneratedCorrectly(boProjectGenerator);
        }

        [Test]
        public void TestGenerate_CreatesClassDefsFile()
        {
            //---------------Set up test pack-------------------
            BoProjectGenerator boProjectGenerator = CreateBoProjectReadyToGenerate();
            //---------------Assert Precondition----------------
            Assert.IsNotNull(boProjectGenerator.SolutionGenerator.ClassDefsString);
            //---------------Execute Test ----------------------
            boProjectGenerator.Generate();
            //---------------Test Result -----------------------
            string path = boProjectGenerator.ProjectPath + Path.DirectorySeparatorChar + "ClassDefs.xml";
            Assert.IsTrue(File.Exists(path));
            string content= File.ReadAllText(path);
            Assert.AreEqual(boProjectGenerator.SolutionGenerator.ClassDefsString, content);
        }

        public abstract class TestBoProjectGenerator_GeneratedFile : TestProjectGeneratorBase_GeneratedFile
        {
            protected override IProjectGenerator CreateProjectReadyToGenerate()
            {
                return CreateBoProjectReadyToGenerate();
            }
        }

        public class TestBoProjectGenerator_GeneratedFile_SampleClass : TestBoProjectGenerator_GeneratedFile
        {
            private string _className;

            public TestBoProjectGenerator_GeneratedFile_SampleClass()
            {
                _className = GetRandomString();
            }

            protected override IProjectGenerator CreateProjectReadyToGenerate()
            {
                BoProjectGenerator projectGenerator = CreateBoProjectReadyToGenerate();
                DMClass dmClass = new DMClass();
                dmClass.ClassNameBO = _className;
                dmClass.Assembly = new DMAssembly(GetRandomString());
                dmClass.Assembly.Solution = new DMSolution(GetRandomString());
                dmClass.Assembly.Solution.BOProjectName = dmClass.Assembly.AssemblyName;
                projectGenerator.SolutionGenerator.ModelClasses.Add(dmClass);
                return projectGenerator;
            }

            protected override void AssertFileGeneratedCorrectly(IProjectGenerator projectGenerator, string fileContents)
            {
                BoProjectGenerator boProjectGenerator = (BoProjectGenerator)projectGenerator;
                IModelClass dmClass = boProjectGenerator.SolutionGenerator.ModelClasses[0];
                StringAssert.Contains("using Habanero.BO;", fileContents);
                StringAssert.Contains(string.Format("namespace {0}", dmClass.AssemblyName), fileContents);
                StringAssert.Contains(string.Format("public partial class {0}", _className), fileContents);
            }

            protected override string GetFileName()
            {
                return _className + ".cs";
            }
        }

        [TestFixture]
        public class TestBoProjectGenerator_GeneratedFile_SampleClass_Def
        {
            private readonly string _className;

            [TestFixtureSetUp]
            public void TestFixtureSetup()
            {
                //Code that is executed before any test is run in this class. If multiple tests
                // are executed then it will still only be called once.
                ClassDef.ClassDefs.Clear();
                ClassDef.ClassDefs.Add(new XmlClassDefsLoader(BOBroker.GetClassDefsXml(), new DtdLoader()).LoadClassDefs());

            }

            [SetUp]
            public void SetupTest()
            {
                BORegistry.DataAccessor = new DataAccessorInMemory();
            }

            [Test]
            public void TestGenerate_GeneratesFile_IfDoesNotExist()
            {
                //---------------Set up test pack-------------------
                IProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                string fileName = Path.Combine(projectGenerator.ProjectPath, GetFileName());
                //---------------Assert Precondition----------------
                Assert.IsFalse(File.Exists(fileName));
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                Assert.IsTrue(Directory.Exists(projectGenerator.ProjectPath), "Folder should exist.");
                Assert.IsTrue(File.Exists(fileName), "File should have been generated because it didn't exist.");
            }

            [Test]
            public void TestGenerate_DoesRegenerate_IfExists()
            {
                //---------------Set up test pack-------------------
                IProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                projectGenerator.Generate();
                string fileName = Path.Combine(projectGenerator.ProjectPath, GetFileName());
                string tempFileContents = GetRandomString();
                File.WriteAllText(fileName, tempFileContents);
                //---------------Assert Precondition----------------
                Assert.AreEqual(tempFileContents, File.ReadAllText(fileName));
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                Assert.AreNotEqual(tempFileContents, File.ReadAllText(fileName));
            }

            [Test]
            public void TestFileAddedToProject()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                //---------------Assert Precondition----------------
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                ProjectFileManager projectFileManager = new ProjectFileManager(projectGenerator.ProjectFileName, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
                string fileName = Path.Combine(projectGenerator.ProjectPath, GetFileName());
                string stubFileName = Path.Combine(projectGenerator.ProjectPath, _className + ".cs");
                Assert.IsTrue(projectFileManager.HasCodeFile(fileName, stubFileName), "File Should be added to the project.");
            }

            [Test]
            public void TestInheritsFromSuperClass_AddsUsingIfDifferentSuperClassAssembly()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                AddSuperClass(dmClass, new DMAssembly(GetRandomString()));
                //---------------Assert Precondition----------------
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("public partial class {0} : {1}", modelClass.ClassName, modelClass.SuperClassName), contents);
                StringAssert.Contains(string.Format("using {0};", modelClass.SuperClassAssemblyName), contents);
            }

            [Test]
            public void TestInheritsFromSuperClass_NoUsingIfSameSuperClassAssembly()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                AddSuperClass(dmClass, dmClass.Assembly);
                //---------------Assert Precondition----------------
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("public partial class {0} : {1}", modelClass.ClassName, modelClass.SuperClassName), contents);
                Assert.IsFalse(contents.Contains(string.Format("using {0};", modelClass.SuperClassAssemblyName)));
            }

            [Test]
            public void TestInheritsFromNothing()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                IModelClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                //---------------Assert Precondition----------------
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath,  dmClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("public partial class {0} : BusinessObject", dmClass.ClassName), contents);
            }

            [Test]
            public void Test_PropertyGeneration_WhenNonValueType_ShouldCreateDeclaration()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMPropertyType propertyType;
                DMProperty dmProperty = CreateDMPropertyWithCustomType(out propertyType);
                dmProperty.Class = dmClass;

                //---------------Assert Precondition----------------
                Assert.AreEqual(1, dmClass.Properties.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelProperty modelProperty = dmClass.Properties[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("public virtual {0} {1}", propertyType.PropertyTypeFullName, modelProperty.PropertyName), contents);
            }

            [Test]
            public void Test_PropertyGeneration_ShouldAddDescriptionAsComment()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMPropertyType propertyType;
                DMProperty dmProperty = CreateDMPropertyWithCustomType(out propertyType);
                dmProperty.Class = dmClass;
                string description = TestUtilsShared.GetRandomString();
                dmProperty.Description = description;

                //---------------Assert Precondition----------------
                Assert.AreEqual(1, dmClass.Properties.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelProperty modelProperty = dmClass.Properties[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("// {0}", description), contents);
            }

            [Test]
            public void Test_PropertyGeneration_WhenGenerateCodeIsFalse_ShouldNotCreateProperty()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMPropertyType propertyType;
                DMProperty dmProperty = CreateDMPropertyWithCustomType(out propertyType);
                dmProperty.Class = dmClass;
                dmProperty.GenerateCode = false;

                //---------------Assert Precondition----------------
                Assert.IsFalse(dmProperty.GenerateCode);
                Assert.AreEqual(1, dmClass.Properties.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelProperty modelProperty = dmClass.Properties[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.DoesNotContain(string.Format("public virtual {0} {1}", propertyType.PropertyTypeFullName, modelProperty.PropertyName), contents);
            }

            [Test]
            public void Test_PropertyGeneration_WhenSuperClassProperty_ShouldNotCreateProperty()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                dmClass.Solution.DefaultAssembly = dmClass.Assembly;
                DMInheritanceRelationship inheritanceRelationship = new DMInheritanceRelationship();
                DMClass superClass = TestUtilsDMClass.CreateDMClassWithObjectIdentity(dmClass.Solution);
                inheritanceRelationship.SubClass = dmClass;
                inheritanceRelationship.SuperClass = superClass;
                TestUtilsShared.UpdateDMInheritanceRelationshipWithValidData(inheritanceRelationship);                
                DMPropertyType propertyType;
                DMProperty dmProperty = CreateDMPropertyWithCustomType(out propertyType);
                dmProperty.PropertyName = "SuperClass_" + dmProperty.PropertyName;
                dmProperty.Class = superClass;
                dmProperty.GenerateCode = true;

                //---------------Assert Precondition----------------
                Assert.IsTrue(dmProperty.GenerateCode);
                Assert.IsTrue(dmClass.AllProperties.Contains(dmProperty));
                Assert.IsFalse(dmClass.Properties.Contains(dmProperty));
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelProperty modelProperty = dmProperty;
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.DoesNotContain(string.Format("public virtual {0} {1}", propertyType.PropertyTypeFullName, modelProperty.PropertyName), contents);
            }

            [Test]
            public void Test_PropertyGeneration_WhenValueType_ShouldCreateDeclarationWithNullable()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMPropertyType propertyType;
                DMProperty dmProperty = CreateDMPropertyWithCustomType(out propertyType);
                dmProperty.Class = dmClass;
                propertyType.AssemblyName = "System";
                propertyType.PropertyTypeName = "Guid";
                //---------------Assert Precondition----------------
                Assert.AreEqual(1, dmClass.Properties.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelProperty modelProperty = dmClass.Properties[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("public virtual {0}? {1}", propertyType.PropertyTypeFullName, modelProperty.PropertyName), contents);
            }

            [Test]
            public void Test_PropertyGeneration_WhenNonValueType_ShouldCreateGetter()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMPropertyType propertyType;
                DMProperty dmProperty = CreateDMPropertyWithCustomType(out propertyType);
                dmProperty.Class = dmClass;

                //---------------Assert Precondition----------------
                Assert.AreEqual(1, dmClass.Properties.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelProperty modelProperty = dmClass.Properties[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("return (({0})(base.GetPropertyValue(\"{1}\")));", propertyType.PropertyTypeFullName, modelProperty.PropertyName), contents);
            }

            [Test]
            public void Test_PropertyGeneration_WhenValueType_ShouldCreateGetterWithNullableCast()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMPropertyType propertyType;
                DMProperty dmProperty = CreateDMPropertyWithCustomType(out propertyType);
                dmProperty.Class = dmClass;
                propertyType.AssemblyName = "System";
                propertyType.PropertyTypeName = "Guid";

                //---------------Assert Precondition----------------
                Assert.AreEqual(1, dmClass.Properties.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelProperty modelProperty = dmClass.Properties[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("return (({0}?)(base.GetPropertyValue(\"{1}\")));", propertyType.PropertyTypeFullName, modelProperty.PropertyName), contents);
            }

            [Test]
            public void Test_PropertyGeneration_ShouldCreateSetter()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMPropertyType propertyType;
                DMProperty dmProperty = CreateDMPropertyWithCustomType(out propertyType);
                dmProperty.Class = dmClass;

                //---------------Assert Precondition----------------
                Assert.AreEqual(1, dmClass.Properties.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelProperty modelProperty = dmClass.Properties[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("base.SetPropertyValue(\"{0}\", value);", modelProperty.PropertyName), contents);
            }

            private static DMProperty CreateDMPropertyWithCustomType(out DMPropertyType propertyType)
            {
                DMProperty dmProperty = new DMProperty();
                dmProperty.PropertyName = "PropertyName" + GetRandomString();

                propertyType = new DMPropertyType();
                propertyType.AssemblyName = "TypeAssemblyName" + GetRandomString();
                propertyType.PropertyTypeName = "TypeName" + GetRandomString();

                dmProperty.PropertyType = propertyType;
                return dmProperty;
            }

            [Test]
            public void Test_RelationshipGeneration_WhenMultiple_ShouldCreateCorrectDeclaration()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Multiple);
                dmClass.OwnerRelationships.Add(relationship);
                //---------------Assert Precondition----------------
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelRelationship modelRelationship = modelClass.Relationships[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("public virtual BusinessObjectCollection<{0}.{1}> {2}",
                    modelRelationship.RelatedAssembly, modelRelationship.RelatedClass, modelRelationship.RelationshipName), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenMultiple_ShouldAddDescriptionAsComment()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Multiple);
                dmClass.OwnerRelationships.Add(relationship);
                string description = TestUtilsShared.GetRandomString();
                relationship.RelationshipDescription = description;
                //---------------Assert Precondition----------------
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("// {0}", description), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenMultiple_WithGenerateCodeIsFalse_ShouldNotCreateRelationship()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Multiple);
                dmClass.OwnerRelationships.Add(relationship);
                relationship.GenerateCode = false;  
                //---------------Assert Precondition----------------
                Assert.IsFalse(relationship.GenerateCode);
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelRelationship modelRelationship = modelClass.Relationships[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.DoesNotContain(string.Format("public virtual BusinessObjectCollection<{0}.{1}> {2}",
                    modelRelationship.RelatedAssembly, modelRelationship.RelatedClass, modelRelationship.RelationshipName), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenMultiple_ShouldNotCreateSingleDeclaration()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Multiple);
                dmClass.OwnerRelationships.Add(relationship);
                //---------------Assert Precondition----------------
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelRelationship modelRelationship = modelClass.Relationships[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.DoesNotContain(string.Format("public virtual {0}.{1} {2}",
                    modelRelationship.RelatedAssembly, modelRelationship.RelatedClass, modelRelationship.RelationshipName), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenMultiple_ShouldCreateCorrectGetter()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Multiple);
                dmClass.OwnerRelationships.Add(relationship);
                //---------------Assert Precondition----------------
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelRelationship modelRelationship = modelClass.Relationships[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("return Relationships.GetRelatedCollection<{0}.{1}>(\"{2}\");",
                    modelRelationship.RelatedAssembly, modelRelationship.RelatedClass, modelRelationship.RelationshipName), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenSingle_ShouldCreateCorrectDeclaration()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Single);
                dmClass.OwnerRelationships.Add(relationship);
                //---------------Assert Precondition----------------
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelRelationship modelRelationship = modelClass.Relationships[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("public virtual {0}.{1} {2}",
                    modelRelationship.RelatedAssembly, modelRelationship.RelatedClass, modelRelationship.RelationshipName), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenSingle_ShouldAddDescriptionAsComment()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Single);
                dmClass.OwnerRelationships.Add(relationship);
                string description = TestUtilsShared.GetRandomString();
                relationship.RelationshipDescription = description;
                //---------------Assert Precondition----------------
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("// {0}", description), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenSingle_WithGenerateCodeIsFalse_ShouldNotCreateRelationship()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Single);
                dmClass.OwnerRelationships.Add(relationship);
                relationship.GenerateCode = false;
                //---------------Assert Precondition----------------
                Assert.IsFalse(relationship.GenerateCode);
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelRelationship modelRelationship = modelClass.Relationships[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.DoesNotContain(string.Format("public virtual {0}.{1} {2}",
                    modelRelationship.RelatedAssembly, modelRelationship.RelatedClass, modelRelationship.RelationshipName), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenSingle_AndSuperClassRelationship_ShouldNotCreateRelationship()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                dmClass.Solution.DefaultAssembly = dmClass.Assembly;
                DMInheritanceRelationship inheritanceRelationship = new DMInheritanceRelationship();
                DMClass superClass = TestUtilsDMClass.CreateDMClassWithObjectIdentity(dmClass.Solution);
                inheritanceRelationship.SubClass = dmClass;
                inheritanceRelationship.SuperClass = superClass;
                TestUtilsShared.UpdateDMInheritanceRelationshipWithValidData(inheritanceRelationship);

                DMRelationship relationship = CreateRelationship(Cardinality.Single);
                relationship.RelationshipName = "SuperClass_" + relationship.RelationshipName;
                relationship.OwnerClass = superClass;
                relationship.GenerateCode = true;
                //---------------Assert Precondition----------------
                Assert.IsTrue(relationship.GenerateCode);
                Assert.IsFalse(dmClass.OwnerRelationships.Contains(relationship));
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelRelationship modelRelationship = relationship;
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.DoesNotContain(string.Format("public virtual {0}.{1} {2}",
                    modelRelationship.RelatedAssembly, modelRelationship.RelatedClass, modelRelationship.RelationshipName), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenSingle_ShouldNotCreateMultipleDeclaration()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Single);
                dmClass.OwnerRelationships.Add(relationship);
                //---------------Assert Precondition----------------
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelRelationship modelRelationship = modelClass.Relationships[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.DoesNotContain(string.Format("public virtual BusinessObjectCollection<{0}.{1}> {2}",
                    modelRelationship.RelatedAssembly, modelRelationship.RelatedClass, modelRelationship.RelationshipName), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenSingle_ShouldCreateCorrectGetter()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Single);
                dmClass.OwnerRelationships.Add(relationship);
                //---------------Assert Precondition----------------
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelRelationship modelRelationship = modelClass.Relationships[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("return Relationships.GetRelatedObject<{0}.{1}>(\"{2}\");",
                    modelRelationship.RelatedAssembly, modelRelationship.RelatedClass, modelRelationship.RelationshipName), contents);
            }

            [Test]
            public void Test_RelationshipGeneration_WhenSingle_ShouldCreateCorrectSetter()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                DMRelationship relationship = CreateRelationship(Cardinality.Single);
                dmClass.OwnerRelationships.Add(relationship);
                //---------------Assert Precondition----------------
                Assert.AreEqual(1, ((IModelClass)dmClass).AllRelationships.Count);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                IModelClass modelClass = dmClass;
                IModelRelationship modelRelationship = modelClass.Relationships[0];
                string contents = File.ReadAllText(Path.Combine(projectGenerator.ProjectPath, modelClass.ClassName + ".Def.cs"));
                StringAssert.Contains(string.Format("Relationships.SetRelatedObject(\"{0}\", value);", modelRelationship.RelationshipName), contents);
            }

            private DMRelationship CreateRelationship(Cardinality cardinality)
            {
                DMClass relatedClass = new DMClass();
                relatedClass.ClassNameBO = "RelatedClass" + GetRandomString();
                relatedClass.Assembly = new DMAssembly("RelatedClassAssembly" + GetRandomString());

                DMRelationship relationship = new DMRelationship();
                relationship.Cardinality = cardinality;
                relationship.RelationshipName = "Relationship" + GetRandomString();
                relationship.RelatedClass = relatedClass;
                return relationship;
            }

            [Test]
            public void TestFileAddedToProject_WhenNeedsRegenerationTrue()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                dmClass.NeedsRegeneration = true;
                //---------------Assert Precondition----------------
                Assert.IsTrue(dmClass.NeedsRegeneration);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                ProjectFileManager projectFileManager = new ProjectFileManager(projectGenerator.ProjectFileName, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
                string fileName = Path.Combine(projectGenerator.ProjectPath, GetFileName());
                string stubFileName = Path.Combine(projectGenerator.ProjectPath, _className + ".cs");
                Assert.IsTrue(projectFileManager.HasCodeFile(fileName, stubFileName), "File Should be added to the project.");
            }

            [Test]
            public void TestFileNotAddedToProject_WhenGenerateCodeFalse()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                dmClass.GenerateCode = false;
                //---------------Assert Precondition----------------
                Assert.IsFalse(dmClass.GenerateCode);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                ProjectFileManager projectFileManager = new ProjectFileManager(projectGenerator.ProjectFileName, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
                string fileName = Path.Combine(projectGenerator.ProjectPath, GetFileName());
                string stubFileName = Path.Combine(projectGenerator.ProjectPath, _className + ".cs");
                Assert.IsFalse(projectFileManager.HasCodeFile(fileName, stubFileName), "File Should be added to the project.");
                Assert.IsFalse(projectFileManager.HasCodeFile(stubFileName), "File Should be added to the project.");
            }

            [Test]
            public void TestFileAddedToProject_WhenGenerateCodeTrue()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                dmClass.GenerateCode = true;
                //---------------Assert Precondition----------------
                Assert.IsTrue(dmClass.GenerateCode);
                //---------------Execute Test ----------------------
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                ProjectFileManager projectFileManager = new ProjectFileManager(projectGenerator.ProjectFileName, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
                string fileName = Path.Combine(projectGenerator.ProjectPath, GetFileName());
                string stubFileName = Path.Combine(projectGenerator.ProjectPath, _className + ".cs");
                Assert.IsTrue(projectFileManager.HasCodeFile(fileName, stubFileName), "File Should be added to the project.");
            }

            [Test]
            public void Test_DefFileAddedToProject_WhenDoesNotExist_GenerateCodeTrue_AndNeedsRegenerationSetToFalse()
            {
                //---------------Set up test pack-------------------
                BoProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
                DMClass dmClass = (DMClass)projectGenerator.SolutionGenerator.ModelClasses[0];
                dmClass.NeedsRegeneration = false;
                dmClass.GenerateCode = false;
                projectGenerator.Generate();
                //---------------Assert Precondition----------------
                ProjectFileManager projectFileManager = new ProjectFileManager(projectGenerator.ProjectFileName, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
                string fileName = Path.Combine(projectGenerator.ProjectPath, GetFileName());
                string stubFileName = Path.Combine(projectGenerator.ProjectPath, _className + ".cs");
                Assert.IsFalse(projectFileManager.HasCodeFile(fileName, stubFileName), "File Should be added to the project.");
                Assert.IsFalse(projectFileManager.HasCodeFile(stubFileName), "File Should be added to the project.");
                //---------------Execute Test ----------------------
                dmClass.GenerateCode = true;
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                projectFileManager = new ProjectFileManager(projectGenerator.ProjectFileName, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
                fileName = Path.Combine(projectGenerator.ProjectPath, GetFileName());
                stubFileName = Path.Combine(projectGenerator.ProjectPath, _className + ".cs");
                Assert.IsTrue(projectFileManager.HasCodeFile(stubFileName), "File Should be added to the project.");
                Assert.IsTrue(projectFileManager.HasCodeFile(fileName, stubFileName), "File Should be added to the project.");
            }



            protected string GetFileName()
            {
                return _className + ".Def.cs";
            }

            public TestBoProjectGenerator_GeneratedFile_SampleClass_Def()
            {
                _className = GetRandomString();
            }

            protected BoProjectGenerator CreateProjectReadyToGenerate()
            {
                BoProjectGenerator projectGenerator = CreateBoProjectReadyToGenerate();
                DMClass dmClass = new DMClass();
                dmClass.ClassNameBO = _className;
                dmClass.Assembly = new DMAssembly(GetRandomString());
                dmClass.Assembly.Solution = new DMSolution(GetRandomString());
                dmClass.Assembly.Solution.BOProjectName = dmClass.Assembly.AssemblyName;
                projectGenerator.SolutionGenerator.ModelClasses.Add(dmClass);
                return projectGenerator;
            }

            private void AddSuperClass(DMClass dmClass, DMAssembly dmAssembly)
            {
                DMClass superClass = new DMClass();
                superClass.ClassNameBO = GetRandomString();
                superClass.Assembly = dmAssembly;

                DMInheritanceRelationship dmInheritanceRelationship = new DMInheritanceRelationship();
                dmInheritanceRelationship.SuperClass = superClass;
                dmClass.InheritanceSuperClassRelationship = dmInheritanceRelationship;
            }
        }
    }


}
